package cn.b504.qpcr.impls.data.manager;

import azure2java.qpcradapter.QpcrUtils;
import azure2java.qpcradapter.adapter.*;
import azure2java.qpcradapter.entity.ProtocolBean;
import azure2java.qpcradapter.entity.WorkspaceBean;
import cn.b504.qpcr.entity.data.MeltData;
import cn.b504.qpcr.entity.data.QuantificationData;
import cn.b504.qpcr.entity.data.manager.*;
import cn.b504.qpcr.interfaces.data.manager.DataManagerDataBuilder;
import cn.b504.qpcr.interfaces.data.manager.DataManager;
import cn.b504.qpcr.utils.FileUtils;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Service
public class DataManagerImpl implements DataManager {
  private final QpcrUtils qpcr;
  private final DataManagerDataBuilder builder;
  private final String tmpPath;

  public DataManagerImpl(QpcrUtils qpcr, DataManagerDataBuilder builder, String tmpPath) {
    this.qpcr = qpcr;
    this.builder = builder;
    this.tmpPath = tmpPath;
  }

  @Override
  public Result getResult(String azdFilePath) {
    DataProcesserAdapter processor = new DataProcesserAdapter();
    // 读取这个 AZD 文件到 processor 对象中
    if (!processor.fromFile(azdFilePath)) {
      FileUtils.deleteFile(azdFilePath);
      return new Result();
    }
    Future<QuantificationData> futurePcr = builder.buildPcr(processor, azdFilePath + ".pcr.csv");
    Future<MeltData> futureMelt = builder.buildMelt(processor, azdFilePath + ".melt.csv");

    do {
      Thread.yield();
    } while (!futurePcr.isDone() || !futureMelt.isDone());

    FileUtils.deleteFile(azdFilePath);
    try {
      return new Result(futurePcr.get(), futureMelt.get());
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
      return new Result();
    }
  }

  @Override
  public Result getResult(@NonNull DM dm) {
    DeviceInfoAdapter deviceInfo = null;
    ConnectedDeviceDictionary[] connectedDevices = qpcr.getConnectedDevices();
    for (ConnectedDeviceDictionary connectedDevice : connectedDevices) {
      if (!dm.getIp().equals(connectedDevice.getKey().getConnectPort())) {
        continue;
      }
      deviceInfo = connectedDevice.getKey();
      break;
    }
    if (deviceInfo == null) {
      return new Result();
    }

    String experimentName = dm.getExperimentDataName();

    ExperimentDataInfoAdapter experimentDataInfo = new ExperimentDataInfoAdapter();
    experimentDataInfo.setWorkSpaceName(dm.getWorkSpaceName());
    experimentDataInfo.setProgramName(dm.getProtocolName());
    experimentDataInfo.setExperimentDataName(experimentName);
    experimentDataInfo.setExperimentBeginDage(dm.getExperimentBeginDate());
    experimentDataInfo.setExperimentEndDate(dm.getExperimentEndDate());

    // 将临时文件夹路径和相关信息传入 GetExperimentDataFiles() 方法中，这样就在这个路径中生成了以 experimentName 为名、以 AZD 为后缀的文件
    if (!qpcr.getExperimentDataFiles(deviceInfo, new ExperimentDataInfoAdapter[]{experimentDataInfo}, tmpPath)) {
      return new Result();
    }
    return getResult(tmpPath + File.separator + experimentName + ".AZD");
  }

  @Override
  public List<Workspace> getWorkspaces(@NonNull String ip) {
    // 使用 ip 获取仪器，然后获取目录结构
    ConnectedDeviceAdapter connectedDevice = null;
    WorkspaceBean[] workspaces = null;
    for (ConnectedDeviceDictionary connectedDeviceDictionary : qpcr.getConnectedDevices()) {
      DeviceInfoAdapter deviceInfo = connectedDeviceDictionary.getKey();
      if (!ip.equals(deviceInfo.getConnectPort())) {
        continue;
      }
      if (!qpcr.getExperimentDataSummary(deviceInfo)) {
        return new ArrayList<>();
      }
      connectedDevice = connectedDeviceDictionary.getValue();
      if (connectedDevice == null) {
        return new ArrayList<>();
      }
      workspaces = connectedDevice.getDataManagerWorkspace();
      break;
    }
    if (connectedDevice == null || workspaces == null) {
      return new ArrayList<>();
    }
    List<Workspace> directoryWorkspaces = new ArrayList<>();
    for (WorkspaceBean workSpace : workspaces) {
      ProtocolBean[] protocols = workSpace.getProtocols();
      List<Protocol> directoryProtocols = new ArrayList<>();
      for (ProtocolBean protocol : protocols) {
        ExperimentDataInfoAdapter[] experimentDataInfoAdapters = protocol.getExperimentDataInfo();
        List<Experiment> directoryExperiments = new ArrayList<>();
        for (ExperimentDataInfoAdapter experimentDataInfoAdapter : experimentDataInfoAdapters) {
          directoryExperiments.add(new Experiment(
              experimentDataInfoAdapter.getExperimentDataName(),
              experimentDataInfoAdapter.getExperimentBeginDate(),
              experimentDataInfoAdapter.getExperimentEndDate()
          ));
        }
        directoryProtocols.add(new Protocol(protocol.getName(), directoryExperiments));
      }
      directoryWorkspaces.add(new Workspace(workSpace.getName(), directoryProtocols));
    }
    return directoryWorkspaces;
  }
}
